package com.zerocarbon.framework.db.mybatis.typehandler;

import com.zerocarbon.framework.common.utils.RsaUtils;
import org.apache.ibatis.type.Alias;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

import javax.crypto.Cipher;
import java.security.interfaces.RSAPublicKey;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Base64;

/**
 * 字段加密、解密
 * @author wyf
 * 2020年8月17日
 */
@Alias("fieldEncrypt")
//@MappedTypes(String.class)
//@MappedJdbcTypes(JdbcType.VARCHAR)
public class FieldEncryptTypeHandler<T extends Object> extends BaseTypeHandler<T> {
	
	/**
	 * 公私钥，后台改成从配置文件中读取，各环境可以设置成不一样
	 */
	private final static String publicKeyBase64 = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQClz1f39oJi0sDRmG2+5tOmR/+VptiYyo8aGIQByuDrln3NDCjxxIUQ31x66ksRn1HhBw02FRfm17020At7ARh6EGapxslR5+HKBvGUT2zBjI7Qe1a7v438v3LVmmSRWmZQuFyaU0wkblstkHRnvSJswaYhoEDYxWgYRJeZVBWrVQIDAQAB";
	
	private final static String privateKeyBase64 = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKXPV/f2gmLSwNGYbb7m06ZH/5Wm2JjKjxoYhAHK4OuWfc0MKPHEhRDfXHrqSxGfUeEHDTYVF+bXvTbQC3sBGHoQZqnGyVHn4coG8ZRPbMGMjtB7Vru/jfy/ctWaZJFaZlC4XJpTTCRuWy2QdGe9ImzBpiGgQNjFaBhEl5lUFatVAgMBAAECgYAYQ00GFeZie6CHixyUEMbr0CFQTsfnI8zo7qlycbOUBcOG276qEi2+mFC6E8rEW2Hp4dRHE7MZrnwbpznm1/Qyu7n91StH95DShNHvvgNStvCwYHYCs9VtyDcMxvWLFEWansMFLx5HOUrsTijUC2MLz0B5zXtt/csE0jbLov1FiQJBAOeXQjqwPZ5qYss7uwHUFKaRRWDkgOoe36cjoI+/oV/YrR6heaB7HV19S14jKW4aOBfZT3fHdSfKLkVpN4SrUeMCQQC3STJJmVex0hvbi3Fo2YYGMyoC8doLMXWtPgr4iXDq/7UaMcJo8Mjuv01tEX3V+F7iz9YA06FoTsZ10lfwYrNnAkEAlsnOjoXX6QBdyPPgJCWhOH7XzGmbYlStzJaO4WmlOdHLjmkW1x2yFgARhX6haBXcNfMBIf0VU835aKpEQraFfwJBAKqO6MbodVy6QsYomt6RHVEDp6KZ4OftnK4cQCVL8NIeJi88AseY2cKiLrDCSDEnMVUrRt/6EAd61t+pX8AIeR0CQEZ01QGDcsEHorGrCIiwdoffNMVF23F6vbh/xSSWTc8+hMHmyLy2AeF8Z0JD8YkmMwhraqsxlV8A8jxDAvPZcvQ=";
	
	@Override
    public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
        if (parameter == null) {
            ps.setString(i, null);
        } else {
        	ps.setString(i, encrypt(parameter.toString()));
        }
    }

    @SuppressWarnings("unchecked")
	@Override
    public T getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return (T) decrypt(rs.getString(columnName));
    }

    @SuppressWarnings("unchecked")
	@Override
    public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
    	return (T) decrypt(rs.getString(columnIndex));
    }

    @SuppressWarnings("unchecked")
	@Override
    public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
    	return (T) decrypt(cs.getString(columnIndex));
    }
    
    public static String encrypt(String content) { //公钥加密
        try {
        	RSAPublicKey publicKey = RsaUtils.getRSAPublicKey(publicKeyBase64);
            byte[] output = RsaUtils.rsaSplitCodec(RsaUtils.getEncryptCipher(publicKey), Cipher.ENCRYPT_MODE, content.getBytes("UTF-8"), publicKey.getModulus().bitLength());
            return Base64.getEncoder().encodeToString(output);
        } catch (Exception e){
        	throw new RuntimeException(e);
        }
    }
    
    public static String decrypt(String content) { //私钥解密
    	if(content==null)
    		return null;
        return RsaUtils.decrypt(content, RsaUtils.getRSAPrivateKey(privateKeyBase64));
    }
}
